<?php


namespace app\cms\community\thirdPartyApi\weChat;

use app\cms\community\thirdPartyApi\weChat\lib\payParams;
use iflow\Response;
use WeChat\Exceptions\InvalidDecryptException;
use WeChat\Exceptions\InvalidResponseException;
use WeChat\Exceptions\LocalCacheException;
use WePay\Transfers;
use WePayV3\Contracts\DecryptAes;
use WePayV3\Order;
use WePayV3\Refund;

class Pay extends \app\cms\community\thirdPartyApi\abstracts\Pay
{

    private Order $pay;
    private array $config;

    private array $type = [
        'jsapi' => 'JsApiPay',
        'native' => 'QrApiPay',
        'h5' => 'H5ApiPay'
    ];

    public function __construct(protected payParams $publicParams)
    {
        $this->config = $publicParams -> getConfig();
        $this->pay = new Order($this->config);
    }

    /**
     * 统一下单方法
     * @param string $type
     * @return bool|Response
     */
    public function createOrder(string $type): bool|Response
    {
        // TODO: Implement createOrder() method.
        try {
            $type = strtolower($type);
            if (empty($this->type[$type])) return message() -> nodata('请选择正确的支付类型');
            // 订单参数
            $this->payConfig = [
                'out_trade_no'     => $this->publicParams -> out_trade_no,
                // 订单货币
                'amount'           => [
                    'total'     => sprintf('%.2f', $this->publicParams -> total_fee * 100),
                    "currency"  => $this->publicParams -> currency
                ],
                "payer" => [
                    'openid'    => $this->publicParams -> open_id,
                ],
                'notify_url'       => $this->config['notify_url'],
                'appid'            => $this->config['appid'],
                'mchid'            => $this->config['mch_id'],
                'description'      => $this->publicParams -> body
            ];

            // 验证是否为 二维码支付
            if ($type === 'native') {
                unset($this->payConfig['payer']);
            }

            $this->result = $this->pay -> create($type, $this->payConfig);
            return call_user_func([$this, $this->type[$type]]);
        } catch (\Exception $exception) {
            $this->error = $exception -> getMessage();
        }
        return message() -> nodata($this->error);
    }

    /**
     * 创建退款订单
     * @param array $order 订单信息
     * @param string $notify_url 退款回调地址
     * @return array
     * @throws InvalidResponseException
     */
    public function createRefundOrder(array $order, string $notify_url): array {
        $options['notify_url'] = $notify_url;
        $options['refund'] = $order['total_fee'] * 100;
        $options['funds_account'] = "订单退款";
        $options['reason'] = $order['refund_reason'];
        $options['out_refund_no'] = $order['out_refund_no'];
        return (new Refund($this->config)) -> create($options);
    }

    /**
     * 提现至零钱
     * @param array $options
     * @return array
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function transfersToUserOrder(array $options = []): array {
        return (new Transfers($this->config)) -> create($options);
    }

    /**
     * 创建JSAPI订单方法
     * @return Response
     */
    public function JsApiPay(): Response
    {
        // TODO: Implement JsApiPay() method.
        return message() -> success("创建订单成功", $this->result);
    }

    public function QrApiPay(): Response
    {
        // TODO: Implement QrApiQpy() method.
        return message() -> success('生成支付码成功', $this->result);
    }

    public function H5ApiPay(): Response
    {
        // TODO: Implement H5ApiPay() method.
        return message() -> success('创建订单成功', $this->result);
    }

    /**
     * 微信支付回调通知
     * @throws InvalidDecryptException
     */
    public function notify(callable $call): Response
    {
        $data = request() -> getContent();

        if ($data['event_type'] !== 'TRANSACTION.SUCCESS' && $data['event_type'] !== 'REFUND.SUCCESS') {
            logs('error', '支付阻断，请重新支付', $data);
            return message() -> server_error(502, '支付失败');
        }

        if (isset($data['resource'])) {
            $aes = new DecryptAes($this->config['mch_v3_key']);
            $data['result'] = $aes->decryptToString($data['resource']['associated_data'], $data['resource']['nonce'], $data['resource']['ciphertext']);
        }
        $response = call_user_func($call, $data);
        return $response instanceof Response ? $response : json($response);
    }
}